﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using GameSushi.TweenEngine;
using Microsoft.Xna.Framework.Input;

namespace GameSushi.SourceGame
{
    class SushiBoard
    {
        TweenManager tweenManager = new TweenManager();
        public SushiBoard() 
        {
            matrixSushi = null;
            matrixHeight = 0;
            matrixWidth = 0;
            matrixAlignX = 0;
            matrixAlignY = 0;
        }

        //ma tran 2 chieu de luu mang sushi.
        public Sushi[][] matrixSushi;

        // size of matrix
        public int matrixWidth { get; set; }
        public int matrixHeight { get; set; }

        //aligns botton - left on scene.
        public float matrixAlignX { get; set; }
        public float matrixAlignY { get; set; }

        public void init()
        {
            tweenManager = new TweenManager();
            Tween.SetCombineAttributesLimit(4);
            Tween.RegisterAccessor(typeof(Sushi), new SushiAccessor());

            matrixWidth = GameConfig.MATRIX_WIDTH;
            matrixHeight = GameConfig.MATRIX_HEIGHT;

            matrixAlignX = (GameConfig.VIRTUAL_SCREEN_WIDTH - GameConfig.MATRIX_WIDTH * GameConfig.VIRTUAL_SUSHI_WIDTH - 
                    GameConfig.SUSHI_GAP * (GameConfig.MATRIX_WIDTH - 1) ) / 2;
            matrixAlignY = (GameConfig.VIRTUAL_SCREEN_HEIGHT - GameConfig.MATRIX_HEIGHT * GameConfig.VIRTUAL_SUSHI_HEIGHT -
                    GameConfig.SUSHI_GAP * (GameConfig.MATRIX_HEIGHT - 1)) / 2;

            matrixSushi = new Sushi[matrixHeight][];
            for (int i = 0; i < matrixHeight; i++)
            {
                matrixSushi[i] = new Sushi[matrixWidth];
            }

            initMatrix();
        }

        //init matrix
        public void initMatrix()
        {
            for (int row = 0; row < matrixHeight; row++)
            {
                for (int col = 0; col < matrixWidth; col++)
                {
                    matrixSushi[row][col] = new Sushi(row, col);
                    //matrixSushi[row][col]._pos = positionOfItem(row, col);

                    this.MoveTo(matrixSushi[row][col], new Vector2(0, 0), positionOfItem(row, col), 2000f);
                    //move no xuong duoi
                    //Tween move
                    //Tween.Set(matrixSushi[row][col], SushiAccessor.POS_XY).Target(0, 500).Start(tweenManager);
                    //Tween.To(matrixSushi[row][col], SushiAccessor.POS_XY, 2000f).Delay(10).Repeat(0, 0.2f).Target(positionOfItem(row, col).X, positionOfItem(row, col).Y).Start(tweenManager);
                    //createAndDropSushi(row, col);
                }
            }
            //Tween scale
            //Tween.Set(matrixSushi[3][2], SushiAccessor.SCALE_XY).Target(0.2f).Start(tweenManager);
            //Tween.To(matrixSushi[3][2], SushiAccessor.SCALE_XY, 2000f).Delay(10).Repeat(4, 0.2f).Target(1f).Start(tweenManager);
            //Tween.Set(matrixSushi[2][3], SushiAccessor.SCALE_XY).Target(0.2f).Start(tweenManager);
            //Tween.To(matrixSushi[2][3], SushiAccessor.SCALE_XY, 2000f).Delay(10).Repeat(4, 0.2f).Target(1f).Start(tweenManager);
            //Tween rotation
            //Tween.Set(matrixSushi[3][2], SushiAccessor.ROTATION).Target(0f).Start(tweenManager);
            //Tween.To(matrixSushi[3][2], SushiAccessor.ROTATION, 2000f).Delay(10).Repeat(4, 0.2f).Target(2*(float)Math.PI).Start(tweenManager);
        }

        //create sushi and falling sushi on matrix
        public void createAndDropSushi(int row, int col)
        {
            Tween.To(matrixSushi[row][col], SushiAccessor.POS_XY, 0.5f).Target(0).Start(tweenManager);
        }

        //position of sushi at row + col
        public Vector2 positionOfItem(int row, int col)
        {
            float x = matrixAlignX + (GameConfig.VIRTUAL_SUSHI_WIDTH + GameConfig.SUSHI_GAP) * col + 
                        GameConfig.VIRTUAL_SUSHI_WIDTH / 2;
            float y = matrixAlignY + (GameConfig.VIRTUAL_SUSHI_HEIGHT + GameConfig.SUSHI_GAP) * row + 
                        GameConfig.VIRTUAL_SUSHI_HEIGHT / 2;
            return new Vector2(x, y);
        }

        private Sushi mSushiOne = null;
        private Sushi mSushiTwo = null;
        private Point mSushiOnePoint = new Point(-1, -1);
        private Point mSushiTwoPoint = new Point(-1, -1);

        bool isClick = false;
        public void MouseClick(float deltaTime)
        {
            var mouseState = Mouse.GetState();
            if (mouseState.LeftButton == ButtonState.Pressed && !this.isClick)
            {
                this.isClick = true;
                var mousePosition = new Point(mouseState.X, mouseState.Y);
                //Neu diem duoc chon nho hon maxtrixalign
                int col = (int)(mousePosition.X - matrixAlignX) / (GameConfig.VIRTUAL_SUSHI_WIDTH + GameConfig.SUSHI_GAP);
                int row = (int)(mousePosition.Y - matrixAlignY) / (GameConfig.VIRTUAL_SUSHI_HEIGHT + GameConfig.SUSHI_GAP);
                if (row >= this.matrixHeight || col >= this.matrixWidth || row < 0 || col < 0 ||
                    mousePosition.X < matrixAlignX || mousePosition.Y < matrixAlignY)
                    return;

                //sushi duoc chon se scale len
                this.Scale(matrixSushi[row][col], 0.2f, 1f, 1000f, 100000, 0.2f);
                matrixSushi[row][col]._color = Color.Salmon;
                //Hoan doi vi tri
                if (this.mSushiOne == null)
                {
                    this.mSushiOne = matrixSushi[row][col];
                    this.mSushiOnePoint = new Point(row, col);
                }
                else
                {
                    if (this.mSushiTwo == null && matrixSushi[row][col]._pos != this.mSushiOne._pos)
                    {
                        this.mSushiTwo = matrixSushi[row][col];
                        this.mSushiTwoPoint = new Point(row, col);
                        //Hoan doi position
                        Vector2 posSushiOne = this.mSushiOne._pos;
                        Vector2 posSushiTwo = this.mSushiTwo._pos;
                        this.mSushiOne._pos = posSushiTwo;
                        this.mSushiTwo._pos = posSushiOne;
                        //Doi trong ma tran
                        //Cap nhat thang dau
                        this.mSushiTwo._row = this.mSushiOnePoint.X;
                        this.mSushiTwo._col = this.mSushiOnePoint.Y;
                        //Cap nhat thang sau
                        this.mSushiOne._row = this.mSushiTwoPoint.X;
                        this.mSushiOne._col = this.mSushiTwoPoint.Y;
                        //
                        this.matrixSushi[this.mSushiOnePoint.X][this.mSushiOnePoint.Y] = this.mSushiTwo;
                        this.matrixSushi[this.mSushiTwoPoint.X][this.mSushiTwoPoint.Y] = this.mSushiOne;
                        //
                        //this.MoveTo(sushiOne, posSushiOne, posSushiTwo);
                        //this.MoveTo(sushiTwo, posSushiTwo, posSushiOne);
                        this.mSushiOne._color = Color.White;
                        this.mSushiTwo._color = Color.White;

                        this.SetLines(this.mSushiOne);
                        this.SetLines(this.mSushiTwo);
                        //
                        Tween.KillAll(tweenManager);

                        this.mSushiOne = null;
                        this.mSushiTwo = null;
                    }
                }
            }
            else if(mouseState.LeftButton == ButtonState.Released)
            {
                if (mSushiTwo != null && mSushiTwo != null)
                {
                    mSushiOne = null;
                    mSushiTwo = null;
                }
                this.isClick = false;
            }
        }

        private void SetLines(Sushi sushi)
        {
            int row = sushi._row;
            int col = sushi._col;
            Dictionary<int, List<int>> dicSushi = this.GetOneLine(sushi);
            if (dicSushi.ContainsKey(0))
            {
                for (int i = dicSushi[0][0]; i <= dicSushi[0][1]; ++i)
                {
                    if (row > 0)
                    {
                        for (int j = row; j > 0; j--)
                        {
                            this.SwapSushi(this.matrixSushi[j-1][i], this.matrixSushi[j][i]);
                        }
                    }
                    this.matrixSushi[0][i] = new Sushi(0, i);
                    this.matrixSushi[0][i]._pos = positionOfItem(0, i);
                }
            }

            if (dicSushi.ContainsKey(1))
            {
                for (int i = dicSushi[1][0]; i <= dicSushi[1][1]; ++i)
                {
                    if (row > 0)
                    {
                        for (int j = row; j > 0; j--)
                        {
                            this.SwapSushi(this.matrixSushi[j - 1][i], this.matrixSushi[j][i]);
                        }
                    }
                    this.matrixSushi[0][i] = new Sushi(0, i);
                    this.matrixSushi[0][i]._pos = positionOfItem(0, i);
                }
            }
        }

        private void SwapSushi(Sushi sushiOne, Sushi sushiTwo)
        {
            if(sushiOne != null && sushiTwo != null)
            {
                Point sushiOnePoint = new Point(sushiOne._row, sushiOne._col);
                Point sushiTwoPoint = new Point(sushiTwo._row, sushiTwo._col);
                //Hoan doi position
                Vector2 posSushiOne = sushiOne._pos;
                Vector2 posSushiTwo = sushiTwo._pos;
                sushiOne._pos = posSushiTwo;
                sushiTwo._pos = posSushiOne;
                //Cap nhat thang dau
                sushiOne._row = sushiTwoPoint.X;
                sushiOne._col = sushiTwoPoint.Y;
                //Cap nhat thang sau
                sushiTwo._row = sushiOnePoint.X;
                sushiTwo._col = sushiOnePoint.Y;
                //Doi trong ma tran
                //
                this.matrixSushi[sushiOnePoint.X][sushiOnePoint.Y] = sushiTwo;
                this.matrixSushi[sushiTwoPoint.X][sushiTwoPoint.Y] = sushiOne;
            }
        }

        private Dictionary<int, List<int>> GetOneLine(Sushi sushi)
        {
            int id = sushi._id;
            int start_Hoz = sushi._col;  //bat dau theo chieu ngang
            int end_Hoz = sushi._col;    //ket thuc theo chieu ngang
            int start_Ver = sushi._row;  //bat dau theo chieu doc
            int end_Ver = sushi._row;    //ket thuc theo chieu doc
            Dictionary<int, List<int>> dicSushi = new Dictionary<int, List<int>>(); ;

            //theo chieu ngang tu trai qua phai
            for (int i = sushi._col + 1; i < GameConfig.MATRIX_WIDTH; i++)
            {
                if(i >= 0 && i < GameConfig.MATRIX_WIDTH)
                {
                    if (!(matrixSushi[sushi._row][i]._id == id))
                    {
                        break;
                    }
                    end_Hoz = i;
                }
            }
            //theo chieu ngang tu phai qua trai
            for (int i = sushi._col - 1; i >= 0; i--)
            {
                if (i >= 0 && i < GameConfig.MATRIX_WIDTH)
                {
                    if (!(matrixSushi[sushi._row][i]._id == id))
                    {
                        break;
                    }
                    start_Hoz = i ;
                }
            }
            //check dieu kien an theo chieu ngang
            if ((end_Hoz - start_Hoz) >= 2)
            {
                ////destroy shushi tu start_Hoz toi end_Hoz vs sushi._row
                //for (int i = start_Hoz; i <= end_Hoz; i++)
                //{
                //    this.Scale(matrixSushi[sushi._row][i], 1.5f, 0f);
                //    this.Rotation(matrixSushi[sushi._row][i], 0f, 2 * (float)Math.PI);
                //}
                dicSushi.Add(0, new List<int>(new int[] {start_Hoz, end_Hoz}));
            }

          
            //theo chieu doc tu tren xuong duoi bat dau tu diem sushi._row, sushi._col
            for (int i = sushi._row + 1; i < GameConfig.MATRIX_HEIGHT; i++)
            {
                if (i >= 0 && i < GameConfig.MATRIX_HEIGHT)
                {
                    if (!(matrixSushi[i][sushi._col]._id == id))
                    {
                        break;
                    }
                    end_Ver = i;
                }
            }
            //theo chieu doc tu duoi len tren bat dau tu diem sushi._row, sushi._col
            for (int i = sushi._row - 1; i >= 0; i--)
            {
                if (i >= 0 && i < GameConfig.MATRIX_HEIGHT)
                {
                    if (!(matrixSushi[i][sushi._col]._id == id))
                    {
                        break;
                    }
                    start_Ver = i;
                }
            }

            //check dieu kien an theo chieu doc
            if ((end_Ver - start_Ver) >= 2)
            {
                //destroy shushi tu start_Ver toi end_Ver vs sushi._row
                //for (int i = start_Ver; i <= end_Ver; i++)
                //{
                //    this.Scale(matrixSushi[i][sushi._col], 1.5f, 0f);
                //    this.Rotation(matrixSushi[i][sushi._col], 0f, 2 * (float)Math.PI);
                //}
                dicSushi.Add(1, new List<int>(new int[] { start_Ver, end_Ver }));
            }
            return dicSushi;
        }

        private void MoveTo(Sushi sushi, Vector2 posStart, Vector2 posEnd)
        {
            Tween.Set(sushi, SushiAccessor.POS_XY).Target(posStart.X, posStart.Y).Start(tweenManager);
            Tween.To(sushi, SushiAccessor.POS_XY, 2000f).Delay(10).Target(posEnd.X, posEnd.Y).Start(tweenManager);
        }

        private void MoveTo(Sushi sushi, Vector2 posStart, Vector2 posEnd, float duration)
        {
            Tween.Set(sushi, SushiAccessor.POS_XY).Target(posStart.X, posStart.Y).Start(tweenManager);
            Tween.To(sushi, SushiAccessor.POS_XY, duration).Delay(10).Target(posEnd.X, posEnd.Y).Start(tweenManager);
        }

        private void Rotation(Sushi sushi, float rotationStart, float rotationEnd)
        {
            Tween.Set(sushi, SushiAccessor.ROTATION).Target(rotationStart).Start(tweenManager);
            Tween.To(sushi, SushiAccessor.ROTATION, 2000f).Delay(10).Target(rotationEnd).Start(tweenManager);
        }

        private void Scale(Sushi sushi, float scaleStart, float scaleEnd)
        {
            Tween.Set(sushi, SushiAccessor.SCALE_XY).Target(scaleStart).Start(tweenManager);
            Tween.To(sushi, SushiAccessor.SCALE_XY, 2000f).Delay(10).Target(scaleEnd).Start(tweenManager);
        }

        private void Scale(Sushi sushi, float scaleStart, float scaleEnd, float duration)
        {
            Tween.Set(sushi, SushiAccessor.SCALE_XY).Target(scaleStart).Start(tweenManager);
            Tween.To(sushi, SushiAccessor.SCALE_XY, duration).Delay(10).Target(scaleEnd).Start(tweenManager);
        }

        private void Scale(Sushi sushi, float scaleStart, float scaleEnd, float duration, int repeat, float timeRepeat)
        {
            Tween.Set(sushi, SushiAccessor.SCALE_XY).Target(scaleStart).Start(tweenManager);
            Tween.To(sushi, SushiAccessor.SCALE_XY, duration).Delay(10).Repeat(repeat, timeRepeat).Target(scaleEnd).Start(tweenManager);
        }

        public void Draw(SpriteBatch spriteBatch, Vector3 _screenScale)
        {
            var _scaleMatrix = Matrix.CreateScale(_screenScale);
            spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, _scaleMatrix);

            for (int row = 0; row < matrixHeight; row++)
            {
                for (int col = 0; col < matrixWidth; col++)
                {
                    Vector2 pos = matrixSushi[row][col]._pos;
                    Vector2 posCenter = new Vector2(GameConfig.VIRTUAL_SUSHI_WIDTH/2, GameConfig.VIRTUAL_SUSHI_HEIGHT/2);
                    Sushi sushi = matrixSushi[row][col];
                    spriteBatch.Draw(sushi._textureSushi, sushi._pos, null, sushi._color, sushi._rotation, posCenter, matrixSushi[row][col]._scale, SpriteEffects.None, 0f);
                    //spriteBatch.Draw(matrixSushi[row][col]._textureSushi, new Rectangle((int)matrixSushi[row][col]._pos.X, (int)matrixSushi[row][col]._pos.Y, GameConfig.VIRTUAL_SUSHI_WIDTH, GameConfig.VIRTUAL_SUSHI_HEIGHT), Color.White);
                }
            }
            spriteBatch.End();
        }

        public void Update(float dt) 
        {
            this.MouseClick(dt);
            tweenManager.Update(dt);
        }
    }
}
